﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.ESGRatings.BusinessLogic.Computing;
using Sustainalytics.ESGRatings.Computing.Entities;

using Xunit;
using Xunit.Abstractions;
using Sustainalytics.ESGRatings.Computing.Entities.ESG;

namespace Sustainalytics.ESGComputing.Service.Tests
{
    public class ComparativeGroupIndexesTest
    {
        private readonly IList<Guid> _companyIds = new[]
        {
            new Guid("00000000-0000-0000-0000-000000000001"),
            new Guid("00000000-0000-0000-0000-000000000002"),
            new Guid("00000000-0000-0000-0000-000000000003"),
            new Guid("00000000-0000-0000-0000-000000000004"),
            new Guid("00000000-0000-0000-0000-000000000005"),
            new Guid("00000000-0000-0000-0000-000000000006"),
            new Guid("00000000-0000-0000-0000-000000000007"),
            new Guid("00000000-0000-0000-0000-000000000008"),
            new Guid("00000000-0000-0000-0000-000000000009"),
            new Guid("00000000-0000-0000-0000-000000000010"),
        };

        private readonly ITestOutputHelper _output;

        private readonly ComparativeGroupIndexes<Guid, string, string> _sut;

        public ComparativeGroupIndexesTest(ITestOutputHelper output)
        {
            _output = output;
            _sut = ComparativeGroupIndexes<Guid, string, string>.Create(GetCorporateData(), x => x.Id, x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase, x => x.PeerGroup, StringComparer.InvariantCulture);

        }

        private ICollection<ESGCompanyEntity> GetCorporateData()
        {
            var companies = new List<ESGCompanyEntity>
            {
                new ESGCompanyEntity
                {
                    Id = _companyIds[0],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Construction & Engineering",
                    PeerGroup = "Diversified Financials"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[1],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Construction & Engineering",
                    PeerGroup = "Diversified Financials"
                }
                ,
                new ESGCompanyEntity
                {
                    Id = _companyIds[2],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Construction & Engineering",
                    PeerGroup = "Diversified Financials"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[3],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Capital Goods",
                    PeerGroup = "Electrical Equipment"
                },new ESGCompanyEntity
                {
                    Id = _companyIds[4],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Capital Goods",
                    PeerGroup = "Electrical Equipment"
                },

                new ESGCompanyEntity
                {
                    Id = _companyIds[5],
                    Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Capital Goods",
                    PeerGroup = "Aerospace & Defense"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[6],
                     Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Banks",
                    PeerGroup = "Banks"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[7],
                    Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Banks",
                    PeerGroup = "Banks"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[8],
                    Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Banks",
                    PeerGroup = "Banks"
                },
                new ESGCompanyEntity
                {
                    Id = _companyIds[9],
                    Attributes = ESGRatingsOptions.CompanyAttributesEnum.Public | ESGRatingsOptions.CompanyAttributesEnum.TypeA,
                    IndustryGroup = "Automobiles & Components",
                    PeerGroup = "Auto Components"
                }
            };
            return companies;
        }


        [Fact]
        public void Count_Should_Return_Companies_Count()
        {
            //Arrange

            //Act
            var actual = _sut.Count;
            //Assert
            Assert.Equal(_companyIds.Count, actual);
        }

        [Fact]
        public void GetIndex_For_IndustryGroup_Reordering_OneCompanyInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ToArray();

            //Act
            var actual = _sut.GetIndex(_companyIds[9]);
            //Assert
            var expected = Array.FindIndex(dictionary, item => item.Id == _companyIds[9]);

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GetIndex_For_IndustryGroup_Reordering_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();

            //Act
            var actual = _sut.GetIndex(_companyIds[3]);
            //Assert
            var expected = Array.FindIndex(dictionary, item => item.Id == _companyIds[3]);

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GetReverseIndexCopy_Should_Return_Ordered_Companies_By_IndustryGroup_And_PeerGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();

            //Act
            var actual = _sut.GetReverseIndexCopy();
            //Assert
            var expected = dictionary.Select(x => x.Id).ToArray();

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GetItem_Should_Return_CompanyId_OneCompanyInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();

            //Act
            var index = Array.FindIndex(dictionary, item => item.Id == _companyIds[9]);
            var actual = _sut.GetItem(index);
            //Assert
            var expected = _companyIds[9];

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GetItem_Should_Return_CompanyId_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();

            //Act
            var index = Array.FindIndex(dictionary, item => item.Id == _companyIds[3]);
            var actual = _sut.GetItem(index);
            //Assert
            var expected = _companyIds[3];

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GroupByHeads_IndustryGroup_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();
            foreach (var item in dictionary.Select(x => x.IndustryGroup))
            {
                _output.WriteLine(item);
            }
            var expected = new int[] { 1, 4, 7 };

            //Act
            var actual = _sut.GroupByHeads(ComparativeGroupEnum.IndustryGroup);


            //Assert

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void GroupByHeads_PeerGroup_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();
            foreach (var item in dictionary.Select(x => x.PeerGroup))
            {
                _output.WriteLine(item);
            }
            var expected = new int[] { 1, 4, 5, 7 };

            //Act
            var actual = _sut.GroupByHeads(ComparativeGroupEnum.PeerGroup);


            //Assert

            Assert.Equal(expected, actual);
        }

        [Fact]
        public void GetComparativeGroupCompanies_PeerGroup_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData().ToArray();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();
            var companyId = _companyIds[5];
            var company = companies[5].PeerGroup;


            var expected = dictionary.Where(x => x.PeerGroup == company).Select(x => x.Id);
            foreach (var item in expected)
            {
                _output.WriteLine(item.ToString());
            }

            //Act
            var actual = _sut.GetComparativeGroupCompanies(companyId, ComparativeGroupEnum.PeerGroup);


            //Assert

            Assert.Equal(expected, actual);
        }


        [Fact]
        public void GetComparativeGroupCompanies_IndustryGroup_MultipleCompaniesInGroup()
        {
            //Arrange
            var companies = GetCorporateData().ToArray();
            var dictionary = companies.OrderBy(x => x.IndustryGroup, StringComparer.InvariantCultureIgnoreCase).ThenBy(x => x.PeerGroup, StringComparer.InvariantCulture).ToArray();
            var companyId = _companyIds[5];
            var company = companies[5].IndustryGroup;


            var expected = dictionary.Where(x => x.IndustryGroup == company).Select(x => x.Id);
            foreach (var item in expected)
            {
                _output.WriteLine(item.ToString());
            }

            //Act
            var actual = _sut.GetComparativeGroupCompanies(companyId, ComparativeGroupEnum.IndustryGroup);


            //Assert

            Assert.Equal(expected, actual);
        }
    }
}